package com.mytime.util;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import javax.jdo.Extent;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import org.json.JSONArray;
import org.json.JSONObject;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.mytime.database.Event;
import com.mytime.database.Timetable;
import com.mytime.database.Venue;

public class WSQuery {
	
	/**
	 * Query to get a Venue.
	 * If the Venue doesn't exist, it will return null.	 * 
	 * **/
	public static Venue getVenue(String venueName, PersistenceManager pm) {
		Venue v = null;
		
		Query venueQuery = pm.newQuery(Venue.class);		
		String filter = "name ==\'" + venueName + "\'";
		venueQuery.setFilter(filter);
		
		@SuppressWarnings("unchecked")
		List<Venue> resultVenues = (List<Venue>) venueQuery.execute();
		
		//Venue exists
		if (resultVenues.iterator().hasNext())
			v = resultVenues.iterator().next();
		
		return v;
	}
	
	/**
	 * Query to get an Event.
	 * If the Event doesn't exist, it will return null.
	 * **/	
	public static Event getEvent(String eventName, PersistenceManager pm) {
		Event e = null;
		
		Key eventKey = KeyFactory.createKey(Event.class.getSimpleName(), eventName);
		String encKey = KeyFactory.keyToString(eventKey); 		
		String filter = "encodedKey == \'" + encKey + "\'";
		
		Query query = pm.newQuery(Event.class);
		query.setFilter(filter);
		
		//Executing query	
		@SuppressWarnings("unchecked")
		List<Event> results = (List<Event>) query.execute();
		if (results.iterator().hasNext()) {
			e = results.iterator().next();
		}
		
		return e;
	}
	
	/**
	 * Query to get all Events starting after current time.
	 * **/
	public static List<Timetable> getEvents(PersistenceManager pm) {
		//Gets Events keys
		Query query = pm.newQuery(Timetable.class);
	
		//Get current time
		Date startTime = new Date(System.currentTimeMillis());
		
		//Format: Thu Jan 01 19:00:00 BRT 1970
		String[] completeDate = startTime.toString().split(" ");
		
		Time curTime = new Time(completeDate[3]);
		String filter = " startTime > " + curTime.getTime() +"";
		query.setFilter(filter);

		@SuppressWarnings("unchecked")
		List<Timetable> eventsAfterCurrentTime = (List<Timetable>) query.execute();
				
		return eventsAfterCurrentTime;
	}

	/**
	 * Query to get all Events stored.
	 * **/
	public static List<Event> getAllEvents(PersistenceManager pm, int startTime, 
			String region, ArrayList<String> categoriesList) {
		
		ArrayList<Event> events = new ArrayList<Event>();
		String filter = "";
		
		//TODO: case insentitive query
		//Get all venues located in the given region
		Query venueQuery = pm.newQuery(Venue.class);
		
		if (region != null && region.length() > 0) {
			filter = "region == \'" + region + "\'";
			venueQuery.setFilter(filter);
		}
		
		@SuppressWarnings("unchecked")
		List<Venue> venues = (List<Venue>) venueQuery.execute();
		ArrayList<String> ids = new ArrayList<String>();
		
		for (Venue v: venues) {
			ids.add(v.getEncodedKey());
		}
		
		//Get showtimes from the events in the found venues that starts after the given startTime
		Query timeQuery = pm.newQuery(Timetable.class);
		filter = "startTime >= :p1";
			
		if (ids != null && ids.size() > 0) {
			filter += " && :p2.contains(venueId)";	
		}
		
		timeQuery.setFilter(filter);
			
		@SuppressWarnings("unchecked")
		List<Timetable> showtimes = (List<Timetable>) timeQuery.execute(startTime, ids);
		System.out.println(showtimes.size());
		for (Timetable t: showtimes) {
			Query eventQuery = pm.newQuery(Event.class);
			filter = "encodedKey == \'" + t.getEventId() + "\'";
			
			if (categoriesList.size() > 0)
				filter += " && :p1.contains(category)";
			
			eventQuery.setFilter(filter);
			
			@SuppressWarnings("unchecked")
			List<Event> eventList = (List<Event>) eventQuery.execute(categoriesList);
			
			if (!eventList.iterator().hasNext())
				continue;
			
			//TODO: get venues and showtimes in this method
			Event e = eventList.iterator().next();
			events.add(e);
			System.out.println(e.toJSON());
		}
		
		return events;
	}
	
	/**
	 * Query to get all Venues stored.
	 * **/
	public static List<Venue> getVenues(PersistenceManager pm) {
		ArrayList<Venue> venues = new ArrayList<Venue>();
		Extent<Venue> extent = pm.getExtent(Venue.class, false);		
		
		for (Venue v: extent) {
			venues.add(v);
		}
		
		extent.closeAll();
		return venues;
	}
		
	public static JSONArray getEventsArray(PersistenceManager pm, List<Event> eventsCategoryList) {
		JSONArray result = new JSONArray();
		
		try {
			for (Event e: eventsCategoryList) {
				JSONObject eventObj = e.toJSON();
				JSONArray venuesArray = new JSONArray();
				
				//Get venues
				HashSet<Key> venuesKeys = e.getVenuesList();
				Iterator<Key> itr = venuesKeys.iterator(); 
				while (itr.hasNext()) {
					Key k = itr.next();
					Venue v = pm.getObjectById(Venue.class, k);
					JSONObject venueObj = v.toJSON();
											
					//Get timetable
					Query query = pm.newQuery(Timetable.class);
					String filter = "eventId == \'" + KeyFactory.keyToString(e.getKey()) + "\'";
					filter += " && venueId == \'" + KeyFactory.keyToString(v.getKey()) + "\'";
					query.setFilter(filter);
					
					@SuppressWarnings("unchecked")
					List<Timetable> t = (List<Timetable>) query.execute();
					JSONArray times = new JSONArray();
					for (Timetable entry: t) {
						JSONObject time = new JSONObject();
						time.put("startTime", new Time(entry.getStartTime()).toString());
						time.put("endTime", new Time(entry.getEndTime()).toString());
						times.put(time);
					}
					
					venueObj.put("timetable", times);
					venuesArray.put(venueObj);
				}
				
				eventObj.put("venues", venuesArray);
				result.put(eventObj);
			}
			
		} catch (Exception e ) {
			e.printStackTrace();
		}
		
		return result;
	}

	public static JSONArray getIndividualEventsArray(PersistenceManager pm, List<Event> eventsList) {
		JSONArray result = new JSONArray();
		
		try {
			for (Event e: eventsList) {
				HashSet<Key> venuesList = (HashSet<Key>) e.getVenuesList();
				Iterator<Key> itr = venuesList.iterator();
				
				//Iterate over venues
				while (itr.hasNext()) {
					Key vKey = itr.next();
					
					//Get Venue
					Venue v = pm.getObjectById(Venue.class, vKey);
					
					//Create Object to represent event and its informatiom
					JSONObject eObj = new JSONObject();
										
					//Get venue information
					JSONObject vObj = v.toJSON();
					@SuppressWarnings("unchecked")
					Iterator<String> venueItr = vObj.keys();
										
					//Get timetable
					Query timetableQuery = pm.newQuery(Timetable.class);
					String filter = "eventId == " + KeyFactory.keyToString(e.getKey());
					filter += " && venueId == " + v.getEncodedKey();
					timetableQuery.setFilter(filter);
					
					@SuppressWarnings("unchecked")
					List<Timetable> timetable = (List<Timetable>) timetableQuery.execute();
					
					for (Timetable t: timetable) {
						eObj = e.toJSON();
					
						//Insert venue information on Event Object
						while (venueItr.hasNext()) {
							String key = venueItr.next();
							eObj.put(key, vObj.getString(key));
						}
						eObj.put("startTime", new Time(t.getStartTime()).toString());
						eObj.put("endTime", new Time(t.getEndTime()).toString());

						result.put(eObj);
					}
					
				}
			}
			
		} catch (Exception e) {
			
		}
		return result;
	}
	
}
